package com.maslyk.invitation.entitybean;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.PrePersist;
import javax.persistence.Query;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

import com.maslyk.configuration.ConfigurationManager;
import com.maslyk.invitation.audit.ObjectName;
import com.maslyk.invitation.audit.PropertyLabel;
import com.maslyk.invitation.entitybean.abstrct.GenericEntity;
import com.maslyk.invitation.enums.AdditionalStatusEnum;
import com.maslyk.invitation.enums.OrderStatusEnum;
import com.maslyk.invitation.enums.RecordTypeEnum;
import com.maslyk.invitation.printout.OrderXMLService;
import com.maslyk.invitation.service.PersistenceService;
import com.maslyk.invitation.service.email.MessagingEmailService;

/**
 * 
 * @author kris
 */
@Entity
@Table(name = "ordr")
@ObjectName(label="Zamówienie")
public class Order extends GenericEntity
{
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "id")
	private Integer id;
	@Column(name = "number")
	@PropertyLabel(label="Numer zamówienia")
	private String number;
	@Column(name = "type")
	@Enumerated(EnumType.STRING)
	@PropertyLabel(label="Rodzaj pozycji")
	private RecordTypeEnum type = RecordTypeEnum.ORDER;
	@Column(name = "year")
	@PropertyLabel(label="Rok")
	private Integer year;
	@Column(name = "registrationdate")
	@Temporal(TemporalType.DATE)
	@PropertyLabel(label="Data rejestracji")
	private Date registrationdate = new Date();
	@Column(name = "dateOfReceipt")
	@Temporal(TemporalType.DATE)
	@PropertyLabel(label="Data odbioru")
	private Date dateOfReceipt = null;
	@Column(name = "prepayment")
	@PropertyLabel(label="Zaliczka")
	private BigDecimal prepayment = new BigDecimal(0.00);
	@Column(name = "totalamount")
	@PropertyLabel(label="Suma")
	private BigDecimal totalamount = new BigDecimal(0.00);
	@Column(name = "status")
	@PropertyLabel(label="Status")
	private Integer status = OrderStatusEnum.WPROWADZONE.getStatus();
	@Column(name = "additionalStatus")
	@PropertyLabel(label="Status dodatkowy")
	private Integer additionalStatus = AdditionalStatusEnum.BRAK.getStatus();
	@Column(name = "stuffOrdered")
	@Temporal(TemporalType.DATE)
	@PropertyLabel(label="Data złożenia zamówienia")
	private Date stuffOrdered = null;
	@Column(name = "approved")
	@Temporal(TemporalType.DATE)
	@PropertyLabel(label="Data zatwierdzenia")
	private Date approved = null;
	@Column(name = "note", nullable = true)
	@PropertyLabel(label="Uwagi")
	private String note;
	@Column(name = "shippingcost", nullable = true)
	@PropertyLabel(label="Koszt wysyłki")
	private BigDecimal shippingCost = new BigDecimal(0.00);
	@Column(name = "otherCost", nullable = true)
	@PropertyLabel(label="Inne koszty")
	private BigDecimal otherCost = new BigDecimal(0.00);
	@Column(name = "email")
	@PropertyLabel(label="Email")
	private String email;
	@Column(name = "contactPhone")
	@PropertyLabel(label="Telefon kontaktowy")
	private String contactPhone;
	@Column(name = "clientName")
	@PropertyLabel(label="Klient")
	private String clientName;
	@Column(name = "receipt")
	@PropertyLabel(label="Paragon")
	private String receipt;
	@Column(name = "preReceipt")
	@PropertyLabel(label="Paragon zaliczkowy")
	private String preReceipt;
	@Column(name = "vatinvoice")
	@PropertyLabel(label="Faktura VAT")
	private String VATInvoice;
	@Column(name = "shippingNo")
	@PropertyLabel(label="Numer wysyłki")
	private String shippingNo;
	@Column(name = "shippingAddress")
	@PropertyLabel(label="Adres wysyłki")
	private String shippingAddress;
	@Column(name = "paymentConfirmation")
	@PropertyLabel(label="Dokument wpłaty")
	private String paymentConfirmation;
	@ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY, targetEntity = Salesman.class)
	@JoinColumn(name = "salesmanID")
	private Salesman salesmanID;
	@ManyToOne(cascade = CascadeType.REFRESH, fetch = FetchType.LAZY, targetEntity = Salesman.class)
	@JoinColumn(name = "responsible")
	@PropertyLabel(label="Odpowiedzialny")
	private Salesman responsible;
	@OneToMany(cascade = CascadeType.ALL, mappedBy = "orderID", fetch = FetchType.LAZY)
	private List<Invitation> invitationEntityCollection;

	@OneToMany(cascade = CascadeType.ALL, mappedBy = "order", fetch = FetchType.LAZY)
	private List<Insertion> insertionCollection;

	@OneToMany(cascade = CascadeType.ALL, mappedBy = "order", fetch = FetchType.LAZY)
	private List<Vigniette> vignietteCollection;

	@OneToMany(cascade = CascadeType.ALL, mappedBy = "order", fetch = FetchType.LAZY)
	private List<Product> productCollection;

	@OneToMany(cascade = CascadeType.ALL, mappedBy = "orderID", fetch = FetchType.LAZY)
	private List<Comment> commentList;

	@OneToMany(cascade = CascadeType.ALL, mappedBy = "orderid", fetch = FetchType.LAZY)
	private List<Attachment> attachmentList;

	@Transient
	private String productCodes = null;
	
	//private PropertyChangeSupport pcs = new PropertyChangeSupport( this );
	
	public Order()
	{
	}

	public Order(Integer id)
	{
		this.id = id;
	}

	public Order(Integer id, Date registrationdate, BigDecimal totalamount,
			String bridename, String bridegroom, Date weddingDateTime)
	{
		this.id = id;
		this.registrationdate = registrationdate;
		this.totalamount = totalamount;
	}

	public Integer getId()
	{
		return id;
	}

	public void setId(Integer id)
	{
		this.id = id;
	}

	public Salesman getSalesmanID()
	{
		return salesmanID;
	}

	public void setSalesmanID(Salesman salesmanID)
	{
		// wpisujemy tylko osobe rejestrujaca
		if (this.salesmanID == null)
			this.salesmanID = salesmanID;
	}

	public String getCreatorName()
	{
		return getSalesmanID().toString();
	}

	public String getResponsibleName()
	{
		return getResponsible().toString();
	}

	public String getNumber()
	{
		return number;
	}

	public void setNumber(String number)
	{
		this.number = number;
	}

	public RecordTypeEnum getType() 
	{
		return type;
	}

	public void setType(RecordTypeEnum type) 
	{
		this.type = type;
	}

	public Date getRegistrationdate()
	{
		if (registrationdate == null)
			registrationdate = new Date();

		return registrationdate;
	}

	public void setRegistrationdate(Date registrationdate)
	{
		this.registrationdate = registrationdate;
	}

	public BigDecimal getPrepayment()
	{
		return prepayment;
	}

	public void setPrepayment(BigDecimal prepayment)
	{	
		this.prepayment = prepayment;
	}

	public BigDecimal getTotalamount()
	{
		totalamount = new BigDecimal(0.00);

		for (Invitation invitation : getInvitationEntityCollection())
			totalamount = totalamount.add(invitation.getAmount());

		for (Insertion insertion : getInsertionCollection())
			totalamount = totalamount.add(insertion.getAmount());

		for (Vigniette vigniette : getVignietteCollection())
			totalamount = totalamount.add(vigniette.getAmount());

		for (Product product : getProductCollection())
			totalamount = totalamount.add(product.getAmount());

		// zsumowanie kosztow przesylki i innych kosztow opisanych w uwagach
		if (shippingCost != null)
			totalamount = totalamount.add(shippingCost);
		if (otherCost != null)
			totalamount = totalamount.add(otherCost);

		totalamount = totalamount.setScale(2, BigDecimal.ROUND_HALF_UP);
		return totalamount;
	}

	public BigDecimal getTotalamountForList()
	{
		return this.totalamount;
	}

	public void setTotalamount(BigDecimal totalamount)
	{
		this.totalamount = totalamount;
	}

	public Integer getStatus()
	{
		return status;
	}

	public String getStatusEnum()
	{
		return OrderStatusEnum.getStatus(status).toString();
	}

	public void setStatus(Integer status)
	{
		this.status = status;
	}

	public Integer getAdditionalStatus() {
		return additionalStatus;
	}
	
	public String getAdditionalStatusEnum() {
		return AdditionalStatusEnum.getStatus(additionalStatus).name();
	}

	public void setAdditionalStatus(Integer additionalStatus) {
		this.additionalStatus = additionalStatus;
	}
	
	public Date getStuffOrdered() {
		return stuffOrdered;
	}

	public void setStuffOrdered(Date stuffOrdered) {
		this.stuffOrdered = stuffOrdered;
	}

	public String getNote()
	{
		return note;
	}

	public void setNote(String note)
	{
		this.note = note;
	}

	public BigDecimal getOtherCost()
	{
		return otherCost;
	}

	public void setOtherCost(BigDecimal otherCost)
	{
		this.otherCost = otherCost;
	}

	public BigDecimal getShippingCost()
	{
		return shippingCost;
	}

	public void setShippingCost(BigDecimal shippingCost)
	{
		this.shippingCost = shippingCost;
	}

	public String getEmail()
	{
		return email;
	}

	public void setEmail(String email)
	{
		this.email = email;
	}

	public String getContactPhone()
	{
		return contactPhone;
	}

	public void setContactPhone(String contactPhone)
	{
		this.contactPhone = contactPhone;
	}

	public String getReceipt()
	{
		return receipt;
	}

	public void setReceipt(String receipt)
	{
		this.receipt = receipt;
	}

	public String getPreReceipt()
	{
		return preReceipt;
	}

	public void setPreReceipt(String preReceipt)
	{
		this.preReceipt = preReceipt;
	}

	public String getVATInvoice()
	{
		return VATInvoice;
	}

	public void setVATInvoice(String VATInvoice)
	{
		this.VATInvoice = VATInvoice;
	}

	public Double getRestOfPayment()
	{
		if (totalamount == null)
			return null;

		if (prepayment == null)
			return totalamount.doubleValue();
		else
			return totalamount.doubleValue() - prepayment.doubleValue();
	}

	public Date getDateOfReceipt()
	{
		if (dateOfReceipt == null)
		{
			Calendar cal = Calendar.getInstance();
			cal.setTime(registrationdate);
			cal.add(Calendar.DATE, 14);
			dateOfReceipt = cal.getTime();
		}
		return dateOfReceipt;
	}

	public void setDateOfReceipt(Date dateOfReceipt)
	{
		this.dateOfReceipt = dateOfReceipt;
	}

	/**
	 * metoda bierze dwa wspolczynniki ilosc godzin przez 2 tygodnie - 336 oraz
	 * kolor RGB od 255 do 0
	 */
	public String getColorDateOfReceipt()
	{
		// Double factor=0.756;
		StringBuilder color = new StringBuilder();
		color.append("background-color:rgb(255,");

		long time1 = System.currentTimeMillis() - registrationdate.getTime();
		long time2 = dateOfReceipt.getTime() - registrationdate.getTime();

		double factor = 0.00;

		if (System.currentTimeMillis() > dateOfReceipt.getTime())
			return "background-color:#FF0000"; // jesli data odbioru juz przeszla to ustawiamy na
						  						// czerwono full
		else
			factor = (double)time1 / (double)time2; // w procentach

		long RGB = (long) (255 * (1-factor));
		if (RGB < 0)
			RGB = 0;
		else if (RGB > 255)
			RGB = 255;

		color.append(RGB).append(',').append(RGB).append(')');
		//System.out.println("Order: " + this.number + " " + color.toString() +" factor: " + factor);
		return color.toString();		
	}

	public int getDaysTo()
	{
		// System.out.println("Order: " + this.number + " " +
		// this.dateOfReceipt.getTime() + " current: " +
		// System.currentTimeMillis());
		int result = (int) ((this.dateOfReceipt.getTime() - System
				.currentTimeMillis()) / 86400000);
		return result;
	}

	public List<Invitation> getInvitationEntityCollection()
	{
		if (invitationEntityCollection == null)
			invitationEntityCollection = new ArrayList<Invitation>();
		return invitationEntityCollection;
	}

	public void setInvitationEntityCollection(
			List<Invitation> invitationEntityCollection)
	{
		this.invitationEntityCollection = invitationEntityCollection;
	}

	public List<Insertion> getInsertionCollection()
	{
		if (insertionCollection == null)
			insertionCollection = new ArrayList<Insertion>();

		return insertionCollection;
	}

	public void setInsertionCollection(List<Insertion> insertionCollection)
	{
		this.insertionCollection = insertionCollection;
	}

	public List<Vigniette> getVignietteCollection()
	{
		if (vignietteCollection == null)
			vignietteCollection = new ArrayList<Vigniette>();

		return vignietteCollection;
	}

	public void setVignietteCollection(List<Vigniette> vignietteCollection)
	{
		this.vignietteCollection = vignietteCollection;
	}

	public List<Comment> getCommentList()
	{
		if (commentList == null)
			commentList = new ArrayList<Comment>();

		return commentList;
	}

	public void setCommentList(List<Comment> commentList)
	{
		this.commentList = commentList;
	}

	public String getClientName()
	{
		return clientName;
	}

	public void setClientName(String clientName)
	{
		this.clientName = clientName;
	}

	public List<Product> getProductCollection()
	{
		if (productCollection == null)
			productCollection = new ArrayList<Product>();

		return productCollection;
	}

	public void setProductCollection(List<Product> productCollection)
	{
		this.productCollection = productCollection;
	}

	public List<Attachment> getAttachmentList()
	{
		return attachmentList;
	}

	public void setAttachmentList(List<Attachment> attachmentList)
	{
		this.attachmentList = attachmentList;
	}

	public Salesman getResponsible()
	{
		return responsible;
	}

	public void setResponsible(Salesman responsible)
	{
		this.responsible = responsible;
	}

	public String getShippingNo()
	{
		return shippingNo;
	}

	public void setShippingNo(String shippingNo)
	{
		this.shippingNo = shippingNo;
	}

	public String getShippingAddress()
	{
		return shippingAddress;
	}

	public void setShippingAddress(String shippingAddress)
	{
		this.shippingAddress = shippingAddress;
	}
	
	public Integer getYear()
	{
		return year;
	}

	public void setYear(Integer year)
	{
		this.year = year;
	}
	
	public Date getApproved() 
	{
		return approved;
	}

	public void setApproved(Date approved) 
	{
		this.approved = approved;
	}
	
	public boolean getApprovedBoolean() 
	{
		return approved != null;
	}

	public void setApprovedBoolean(boolean approved) {
		
		if(approved)
			this.approved = new Date();
		else
			this.approved = null;
	}

	public boolean isOffer()
	{
		return type.equals(RecordTypeEnum.OFFER);
	}

	public String getProductCode()
	{
		if (productCodes != null)
			return productCodes;

		StringBuffer buf = new StringBuffer(20);

		for (Invitation inv : invitationEntityCollection)
			buf.append(inv.getCode()).append(",");

		for (Insertion ins : insertionCollection)
			buf.append(ins.getCode()).append(",");

		for (Vigniette vig : vignietteCollection)
			buf.append(vig.getCode()).append(",");

		for (Product prd : productCollection)
			buf.append(prd.getCode()).append(",");

		productCodes = buf.toString();

		return productCodes;
	}

	@PrePersist
	public void runBeforePersist() throws Exception
	{
		if(type.equals(RecordTypeEnum.OFFER))
			setNumber("O");
		
		if(ConfigurationManager.getInstance().isAutomaticNumberGeneration())
		{
			// generacja numeru zamowienia
			//ustawienie roku na 1 styczen 00h:00m
			Calendar cal = Calendar.getInstance();
			cal.set(Calendar.MONTH, 0);
			cal.set(Calendar.DAY_OF_YEAR, 1);
			cal.set(Calendar.HOUR_OF_DAY, 0);
			cal.set(Calendar.MINUTE, 0);
			
			Long lastNumber = 0L;
			SimpleDateFormat format = new SimpleDateFormat("/MM/yy");
			String monthYear = format.format(new Date());
			Query qry = PersistenceService.getInstance().getEntityManager().createQuery("select max(substring(o.number,2,4)) from Order as o where o.number like :number and o.registrationdate > :date and year is null");
			qry.setParameter("number", this.getNumber() + "%");
			qry.setParameter("date", cal.getTime());
			String lastStrNumber = (String)qry.getSingleResult();
			
			if(lastStrNumber != null && lastStrNumber.length() > 0)
				lastNumber = Long.valueOf(lastStrNumber);
			
			String orderNum = String.format("%04d", ++lastNumber);
			String orderNumber = this.getNumber() + orderNum + monthYear;
	
			this.setNumber(orderNumber);
			// koniec generacji numeru zamowienia
		}
		
        // kod wykonywany tylko w przypadku wstawiania nowego zamowienia
        StringBuffer message = new StringBuffer();
        message.append("U\u017cytkownik <i>"+this.getSalesmanID().getPersonid().getFirstname()+" "+this.getSalesmanID().getPersonid().getSurname()+"</i><br />");
        message.append("zarejestrowa\u0142 nowe zam\u00f3wienie o numerze: <strong>"+this.getNumber()+"</strong>.<br />");
        message.append("Data odbioru zam\u00f3wienia przez Klienta to: "+ OrderXMLService.formatDate(this.getDateOfReceipt(), OrderXMLService.datePattern));
        MessagingEmailService emailService = new MessagingEmailService();
        emailService.sendMessage("biuro@studiografic.pl", message.toString(), "Zarejestrowano nowe zam\u00f3wienie: " + this.getNumber());
	}
	
    public static String getBeanName()
    {
    	return "orderBean";
    }

	public String getKey() 
	{
		return number;
	}

	@Override
	public Object clone() throws CloneNotSupportedException {
		Order ordr = (Order) super.clone();
		ordr.setId(null);
		
		List<Invitation> invitationEntityList = new ArrayList<Invitation>();

		for(Invitation inv : invitationEntityCollection)
		{
			Invitation invTmp = (Invitation)inv.clone();
			invTmp.setOrderID(ordr);
			invitationEntityList.add(invTmp);
		}
		ordr.setInvitationEntityCollection(invitationEntityList);

		List<Insertion> insertionList = new ArrayList<Insertion>();
		
		for(Insertion ins : insertionCollection)
		{
			Insertion  insTmp = (Insertion)ins.clone();
			insTmp.setOrder(ordr);
			insertionList.add(insTmp);
		}
		ordr.setInsertionCollection(insertionList);

		List<Vigniette> vignietteList = new ArrayList<Vigniette>();
		
		for(Vigniette v : vignietteCollection)
		{
			Vigniette vTmp = (Vigniette) v.clone();
			vTmp.setOrder(ordr);
			vignietteList.add(vTmp);
		}
		ordr.setVignietteCollection(vignietteList);
		
		List<Product> productList = new ArrayList<Product>();
		
		for(Product p : productCollection)
		{
			Product pTmp = (Product) p.clone();
			pTmp.setOrder(ordr);
			productList.add(pTmp);
		}
		ordr.setProductCollection(productList);
		
		List<Attachment> attachments = new ArrayList<Attachment>();
		
		for(Attachment a : attachmentList)
		{
			Attachment aTmp = (Attachment) a.clone();
			aTmp.setId(null);
			aTmp.setOrder(ordr);
			attachments.add(aTmp);
		}
		ordr.setAttachmentList(attachments);

		List<Comment> comments = new ArrayList<Comment>();
		
		for (Comment c : commentList)
		{
			Comment cTmp = (Comment) c.clone();
			cTmp.setId(null);
			cTmp.setOrderID(ordr);
			comments.add(cTmp);
		}
		ordr.setCommentList(comments);

		return ordr;
	}

	public String getPaymentConfirmation() {
		return paymentConfirmation;
	}

	public void setPaymentConfirmation(String paymentConfirmation) {
		this.paymentConfirmation = paymentConfirmation;
	}
	
	public boolean isInserted()
	{
		return id != null;
	}
	
	public Comment getLastComment()
	{
		if(commentList == null || commentList.isEmpty())
			return null;
		
		return commentList.get(commentList.size()-1);
	}
}
